﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection.Emit;
using System.Collections;

namespace Axial
{
	public class CodeSegment : CodeStatement
	{
		public List<CodeStatement> Statements { get; private set; }
		public List<IJSWriterable> Outputtables { get; private set; }

		protected CodeSegment()
		{
		}

		public CodeSegment(IEnumerable<CodeStatement> statements)
		{
			Statements = statements.ToList();
			Outputtables = new List<IJSWriterable>();

			// handle the tertiary operator
			for (int i = 1; i < Statements.Count - 2; i++)
			{
				// match the pattern
				ConditionStatement zero = Statements[i + -1] as ConditionStatement;
				CodeStatement one = Statements[i + 0];
				CodeStatement two = Statements[i + 1];

				if (zero != null && one.StackUsage == 1 && zero.FlowTarget == two.StartOffset)
				{
					// possible teriary
					CodeStatement tertiary = CodeStatement.CreateTertiary(Statements.Subset(i - 1, 3));
					Statements.Insert(i - 1, tertiary);
					Statements.RemoveRange(i, 3);
				}
			}

			for (int i = 0; i < Statements.Count; ++i)
			{
				CodeStatement statement = Statements[i];

				// treat a return as a regular statement
				if (statement.GetType() == typeof(ContinueConditionStatement))
				{
					var ifBlock = new ContinueCondition(Statements.SkipWhile(s => s != statement));
					Outputtables.Add(ifBlock);
					// move to the end of the condition
					i = ifBlock.EndOffset > Statements.Last().StartOffset ? Statements.Count : Statements.FindIndex(s => s.StartOffset >= ifBlock.EndOffset) - 1;
				}
				else if (statement.GetType() == typeof(BreakConditionStatement))
				{
					var ifBlock = new BreakCondition(Statements.SkipWhile(s => s != statement));
					Outputtables.Add(ifBlock);
					// move to the end of the condition
					i = ifBlock.EndOffset > Statements.Last().StartOffset ? Statements.Count : Statements.FindIndex(s => s.StartOffset >= ifBlock.EndOffset) - 1;
				}
				else if (statement.GetType() == typeof(ConditionStatement))
				{
					var ifBlock = new IfCondition(Statements.SkipWhile(s => s != statement));
					Outputtables.Add(ifBlock);
					// move to the end of the condition
					i = ifBlock.EndOffset > Statements.Last().StartOffset ? Statements.Count : Statements.FindIndex(s => s.StartOffset == ifBlock.EndOffset) - 1;
				}
				else if (statement.GetType() == typeof(JumpStatement))
				{
					IEnumerable<CodeStatement> therest = Statements.SkipWhile(s => s != statement);
					var whileBlock = new WhileCondition(therest);
					Outputtables.Add(whileBlock);
					// move to the end of the condition
					i = whileBlock.EndOffset > Statements.Last().StartOffset ? Statements.Count : Statements.FindIndex(s => s.StartOffset == whileBlock.EndOffset) - 1;
				}
				else
				{
					if (string.IsNullOrEmpty(statement.Code))
						continue;
					Outputtables.Add(statement);
				}
			}
		}

		public override JSWriter ToJSWriter()
		{
			JSWriter writer = new JSWriter();
			foreach (IJSWriterable output in Outputtables)
				writer.AddWriter(output.ToJSWriter());
			return writer;
		}

		public void RemoveEndingReturn()
		{
			if (!Outputtables.Any())
				return;
			CodeStatement lastStatement = Outputtables.Last() as CodeStatement;
			if (lastStatement == null)
				return;
			if (lastStatement.Code == "return")
				Outputtables.RemoveAt(Outputtables.Count - 1);
		}
	}
}
